package com.xjrsoft.module.oa.utils;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.google.gson.Gson;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.LogCategoryEnum;
import com.xjrsoft.common.enums.MessageType;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.sms.SmsSender;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.config.*;
import com.xjrsoft.module.oa.entity.Message;
import com.xjrsoft.module.oa.service.IMessageService;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.organization.service.IUserService;
import com.xjrsoft.module.system.entity.Log;
import com.xjrsoft.module.system.model.WechatEnterpriseTokenResult;
import com.xjrsoft.module.system.service.ILogService;
import com.xjrsoft.module.workflow.entity.WorkflowExtra;
import com.xjrsoft.module.workflow.model.MessageContent;
import com.xjrsoft.module.workflow.model.NoticePolicyParam;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpMethod;

import javax.swing.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 发送信息工具类
 *
 * @Author: tzx
 * @Date: 2022/10/26 16:59
 */
@Slf4j
public class SendMessageUtil {

    public static final String SCHEDULE_CONTENT_TEMPLATE = "您有一则新的日程《{}》,请及时查看.";

    public static final String WORKFLOW_APPROVE_TEMPLATE = "《{}》等待审批。";


    public static final String WORKFLOW_CIRULATED_TEMPLATE = "《{}》等待查看。";

    public static final String WORKFLOW_TIMEOUT_TEMPLATE = "《{}》任务已超时,等待审批。";

    public static final String WORKFLOW_URGE_TEMPLATE = "《{}》正在催办中";


    /**
     * 添加日程消息
     */
    public static void sendScheduleMessage(Long userId, String objectId, String title) {
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);

        Message message = new Message();
        message.setMessageType(MessageType.SCHEDULE.getCode());
        message.setSendTime(LocalDateTime.now());
        message.setIsRead(YesOrNoEnum.NO.getCode());
        message.setUserId(userId);
        message.setObjectId(objectId);
        message.setMessageContent(StrUtil.format(SCHEDULE_CONTENT_TEMPLATE, title));

        messageService.save(message);
    }

    /**
     * 添加工作流审批消息
     */
    public static void sendWorkflowApproveMessage(NoticePolicyParam param) {
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);

        List<Message> messageList = new ArrayList<>();
        for (Long userId : param.getNoticeUserIds()) {
            Message message = new Message();
            message.setMessageType(MessageType.APPROVE.getCode());
            message.setSendTime(LocalDateTime.now());
            message.setIsRead(YesOrNoEnum.NO.getCode());
            message.setUserId(userId);
            message.setObjectId(param.getTaskId());
            message.setMessageContent(StrUtil.format(WORKFLOW_APPROVE_TEMPLATE, param.getTaskName()));
            message.setProcessId(param.getProcessId());
            message.setSchemaId(param.getSchemaId());

            messageList.add(message);
        }

        messageService.saveBatch(messageList);
    }


    /**
     * 发送工作流审批短信
     */
    public static void sendWorkflowApproveSms(NoticePolicyParam param, String name) {
        IUserService userService = SpringUtil.getBean(IUserService.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        SmsSender smsSender = SpringUtil.getBean(SmsSender.class);

        //获取用户相关信息
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        //构造短信参数，调用短信服务进行短信发送
        if (param.getNoticeUserIds().size() > 0) {
            //获取用户id对应的手机号，用户名
            for (Long userId : param.getNoticeUserIds()) {
                User user = userList.stream().filter(u -> userId.equals(u.getId())).findFirst().orElse(new User());
                String mobile = user.getMobile();
                //调用短信接口服务
                smsSender.sendTimeout(mobile, name);
            }
        }
    }


    /**
     * 添加工作流传阅消息
     */
    public static void sendWorkflowCirculatedMessage(NoticePolicyParam param) {
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);

        List<Message> messageList = new ArrayList<>();
        for (Long userId : param.getNoticeUserIds()) {
            Message message = new Message();
            message.setMessageType(MessageType.CIRCULATED.getCode());
            message.setSendTime(LocalDateTime.now());
            message.setIsRead(YesOrNoEnum.NO.getCode());
            message.setUserId(userId);
            message.setObjectId(param.getTaskId());
            message.setMessageContent(StrUtil.format(WORKFLOW_CIRULATED_TEMPLATE, param.getTaskName()));
            message.setProcessId(param.getProcessId());
            message.setSchemaId(param.getSchemaId());
            messageList.add(message);
        }

        messageService.saveBatch(messageList);
    }

    /**
     * 发送工作流传阅短信
     */
    public static void sendWorkflowCirculatedSms(NoticePolicyParam param, String name) {
        IUserService userService = SpringUtil.getBean(IUserService.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        SmsSender smsSender = SpringUtil.getBean(SmsSender.class);

        //获取用户相关信息
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        //构造短信参数，调用短信服务进行短信发送
        if (param.getNoticeUserIds().size() > 0) {
            //获取用户id对应的手机号，用户名
            for (Long userId : param.getNoticeUserIds()) {
                User user = userList.stream().filter(u -> userId.equals(u.getId())).findFirst().orElse(new User());
                String mobile = user.getMobile();
//                //构建参数,您有一个 %s - %s 创建的《%s》任务已超时,请及时处理.StrUtil.format():使用占位符进行替换
//                String text = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
                //调用短信接口服务
                smsSender.sendCirculated(mobile, name);
            }
        }
    }


    /**
     * 添加工作流超时
     */
    public static void sendWorkflowTimeoutMessage(NoticePolicyParam param) {
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);

        List<Message> messageList = new ArrayList<>();
        for (Long userId : param.getNoticeUserIds()) {
            Message message = new Message();
            //将超时提醒显示在工作流审批消息中
            message.setMessageType(MessageType.APPROVE.getCode());
            message.setSendTime(LocalDateTime.now());
            message.setIsRead(YesOrNoEnum.NO.getCode());
            message.setUserId(userId);
            message.setObjectId(param.getTaskId());
            String format = StrUtil.format(WORKFLOW_TIMEOUT_TEMPLATE, param.getTaskName());
            message.setMessageContent(format);
            message.setProcessId(param.getProcessId());
            message.setSchemaId(param.getSchemaId());
            messageList.add(message);
        }

        messageService.saveBatch(messageList);
    }

    /**
     * 添加工作流超时短信提醒服务
     */
    public static void sendWorkflowTimeoutSms(NoticePolicyParam param, String name) {
        IUserService userService = SpringUtil.getBean(IUserService.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        SmsSender smsSender = SpringUtil.getBean(SmsSender.class);

        //获取用户相关信息
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        //构造短信参数，调用短信服务进行短信发送
        if (param.getNoticeUserIds().size() > 0) {
            //获取用户id对应的手机号，用户名
            for (Long userId : param.getNoticeUserIds()) {
                User user = userList.stream().filter(u -> userId.equals(u.getId())).findFirst().orElse(new User());
                String mobile = user.getMobile();
//                //构建参数,您有一个 %s - %s 创建的《%s》任务已超时,请及时处理.StrUtil.format():使用占位符进行替换
//                String text = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
                //调用短信接口服务
                smsSender.sendTimeout(mobile, name);
            }
        }
    }


    /**
     * 添加工作流超时 断行
     */
    public static void sendWorkflowTimeoutEmail(NoticePolicyParam param) {
        MailAccount mailAccount = SpringUtil.getBean(MailAccount.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);


        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> allEmail = allUser.stream().filter(u -> param.getNoticeUserIds().contains(u.getId())).map(User::getEmail).collect(Collectors.toList());

        String content = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
        MailUtil.send(mailAccount, allEmail, "超时消息提醒", content, false);

    }


    /**
     * 用户审批
     */
    public static void sendWorkflowApproveEmail(NoticePolicyParam param) {
        MailAccount mailAccount = SpringUtil.getBean(MailAccount.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);


        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> allEmail = allUser.stream().filter(u -> param.getNoticeUserIds().contains(u.getId())).map(User::getEmail).collect(Collectors.toList());

        String content = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
        MailUtil.send(mailAccount, allEmail, "用户审批", content, false);
    }

    /**
     * 添加工作流超时 断行
     */
    public static void sendWorkflowCirculatedEmail(NoticePolicyParam param) {
        MailAccount mailAccount = SpringUtil.getBean(MailAccount.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);


        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> allEmail = allUser.stream().filter(u -> param.getNoticeUserIds().contains(u.getId())).map(User::getEmail).collect(Collectors.toList());

        String content = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
        MailUtil.send(mailAccount, allEmail, "用户传阅", content, false);
    }


    /**
     * 添加工作流超时 断行
     */
    public static void sendWorkflowApproveWechat(NoticePolicyParam param) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        WechatEnterpriseConfig wechatEnterpriseConfig = SpringUtil.getBean(WechatEnterpriseConfig.class);

        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.WechatAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.WechatAccessTokenKey);
        }
        else {
            String tokenResult = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wechatEnterpriseConfig.getAppKey() + "&corpsecret=" + wechatEnterpriseConfig.getAppSecret());

            WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);

            accessToken = wechatEnterpriseTokenResult.getAccess_token();
        }

        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        Map<String,Object> paramMap = new HashMap<>();

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.PIPE));

        paramMap.put("touser",touser);
        paramMap.put("msgtype","text");
        paramMap.put("agentid",wechatEnterpriseConfig.getAgentid());

        String content = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
        paramMap.put("content",content);

        String post = HttpUtil.post("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken, paramMap);

    }

    /**
     * 添加工作流传阅消息
     */
    public static void sendWorkflowCirculatedWechat(NoticePolicyParam param) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        WechatEnterpriseConfig wechatEnterpriseConfig = SpringUtil.getBean(WechatEnterpriseConfig.class);

        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.WechatAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.WechatAccessTokenKey);
        }
        else {
            String tokenResult = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wechatEnterpriseConfig.getAppKey() + "&corpsecret=" + wechatEnterpriseConfig.getAppSecret());

            WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);

            accessToken = wechatEnterpriseTokenResult.getAccess_token();
        }

        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        Map<String,Object> paramMap = new HashMap<>();

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.PIPE));

        paramMap.put("touser",touser);
        paramMap.put("msgtype","text");
        paramMap.put("agentid",wechatEnterpriseConfig.getAgentid());

        String content =  StrUtil.format(WORKFLOW_CIRULATED_TEMPLATE, param.getTaskName());
        paramMap.put("content",content);

        String post = HttpUtil.post("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken, paramMap);



    }

    /**
     * 添加工作流超时
     */
    public static void sendWorkflowTimeoutWechat(NoticePolicyParam param) {

        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        WechatEnterpriseConfig wechatEnterpriseConfig = SpringUtil.getBean(WechatEnterpriseConfig.class);

        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.WechatAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.WechatAccessTokenKey);
        }
        else {
            String tokenResult = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wechatEnterpriseConfig.getAppKey() + "&corpsecret=" + wechatEnterpriseConfig.getAppSecret());

            WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);

            accessToken = wechatEnterpriseTokenResult.getAccess_token();
        }

        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        Map<String,Object> paramMap = new HashMap<>();

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.PIPE));

        paramMap.put("touser",touser);
        paramMap.put("msgtype","text");
        paramMap.put("agentid",wechatEnterpriseConfig.getAgentid());

        String content =  StrUtil.format(WORKFLOW_TIMEOUT_TEMPLATE, param.getTaskName());
        paramMap.put("content",content);

        String post = HttpUtil.post("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken, paramMap);




    }



    /**
     * 工作流审批提醒  钉钉
     */
    @SneakyThrows
    public static void sendWorkflowApproveDingtalk(NoticePolicyParam param) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        DingtalkConfig dingtalkConfig =  SpringUtil.getBean(DingtalkConfig.class);


        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.DingtalkAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.DingtalkAccessTokenKey);
        }
        else {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(dingtalkConfig.getAppKey());
            request.setAppsecret(dingtalkConfig.getAppSecret());
            request.setHttpMethod(HttpMethod.GET.name());
            OapiGettokenResponse res = client.execute(request);

            accessToken = res.getAccessToken();
        }
        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.COMMA));

        DingTalkClient sendClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request sendRequest = new OapiMessageCorpconversationAsyncsendV2Request();
        sendRequest.setAgentId(Convert.toLong(dingtalkConfig.getAgentid()));
        sendRequest.setUseridList(touser);
        sendRequest.setToAllUser(false);

        String content = StrUtil.format(SendMessageUtil.WORKFLOW_TIMEOUT_TEMPLATE, param.getStartUserName(), LocalDateTime.now().format(DateTimeFormatter.ofPattern(GlobalConstant.YYYY_MM_DD_HH_MM_SS_24)), param.getSchemaName());
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(content);
        sendRequest.setMsg(msg);

        OapiMessageCorpconversationAsyncsendV2Response rsp = sendClient.execute(sendRequest, accessToken);
    }

    /**
     * 添加工作流传阅消息 钉钉
     */
    @SneakyThrows
    public static void sendWorkflowCirculatedDingtalk(NoticePolicyParam param) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        DingtalkConfig dingtalkConfig =  SpringUtil.getBean(DingtalkConfig.class);


        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.DingtalkAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.DingtalkAccessTokenKey);
        }
        else {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(dingtalkConfig.getAppKey());
            request.setAppsecret(dingtalkConfig.getAppSecret());
            request.setHttpMethod(HttpMethod.GET.name());
            OapiGettokenResponse res = client.execute(request);

            accessToken = res.getAccessToken();
        }
        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.COMMA));

        DingTalkClient sendClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request sendRequest = new OapiMessageCorpconversationAsyncsendV2Request();
        sendRequest.setAgentId(Convert.toLong(dingtalkConfig.getAgentid()));
        sendRequest.setUseridList(touser);
        sendRequest.setToAllUser(false);

        String content =  StrUtil.format(WORKFLOW_CIRULATED_TEMPLATE, param.getTaskName());
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(content);
        sendRequest.setMsg(msg);

        OapiMessageCorpconversationAsyncsendV2Response rsp = sendClient.execute(sendRequest, accessToken);

    }

    /**
     * 添加工作流超时
     */
    @SneakyThrows
    public static void sendWorkflowTimeoutDingtalk(NoticePolicyParam param) {

        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        DingtalkConfig dingtalkConfig =  SpringUtil.getBean(DingtalkConfig.class);


        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.DingtalkAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.DingtalkAccessTokenKey);
        }
        else {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(dingtalkConfig.getAppKey());
            request.setAppsecret(dingtalkConfig.getAppSecret());
            request.setHttpMethod(HttpMethod.GET.name());
            OapiGettokenResponse res = client.execute(request);

            accessToken = res.getAccessToken();
        }
        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });

        List<String> idsList = allUser.stream().map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.COMMA));

        DingTalkClient sendClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request sendRequest = new OapiMessageCorpconversationAsyncsendV2Request();
        sendRequest.setAgentId(Convert.toLong(dingtalkConfig.getAgentid()));
        sendRequest.setUseridList(touser);
        sendRequest.setToAllUser(false);

        String content =  StrUtil.format(WORKFLOW_TIMEOUT_TEMPLATE, param.getTaskName());
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(content);
        sendRequest.setMsg(msg);

        OapiMessageCorpconversationAsyncsendV2Response rsp = sendClient.execute(sendRequest, accessToken);


    }


    /**
     * 系统--消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param content 消息推送的内容
     */
    @SneakyThrows
    public static void sendSystemMessageCommon(List<Long> userIds,String content,Long formId) {
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);

        List<Message> messageList = new ArrayList<>();
        for (Long userId : userIds) {
            Message message = new Message();
            message.setMessageType(MessageType.MESSAGE_SEND.getCode());
            message.setSendTime(LocalDateTime.now());
            message.setIsRead(YesOrNoEnum.NO.getCode());
            message.setUserId(userId);
            message.setMessageContent(content);
            messageList.add(message);
        }

        messageService.saveBatch(messageList);
        //记录日志信息
        String operation = "系统推送系统消息成功，具体内容为：【"+ content + "】";
        insertMessageLogInfo(operation);
    }


    /**
     * 邮件--消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param content 消息推送的内容
     * @param title 标题
     */
    @SneakyThrows
    public static void sendEmailMessageCommon(List<Long> userIds,String content,String title) {
        MailAccount mailAccount = SpringUtil.getBean(MailAccount.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //去重操作
        List<Long> finalUserIds = userIds.stream().distinct().collect(Collectors.toList());
        List<String> allEmail = allUser.stream().filter(u ->ObjectUtil.isNotEmpty(u.getEmail()) && finalUserIds.contains(u.getId())).map(User::getEmail).collect(Collectors.toList());

        if (allEmail.size() > 0){
            //改为异步调用
            CompletableFuture.runAsync(() -> {
                MailUtil.send(mailAccount, allEmail, title, content, false);
                //记录日志信息
                String operation = "系统推送邮件消息成功，具体内容为：【"+ content + "】";
                insertMessageLogInfo(operation);
            });
        }

    }

    /**
     * 钉钉--消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param content 消息推送的内容
     * @param title 标题
     */
    @SneakyThrows
    public static void sendDingtalkMessageCommon(List<Long> userIds,String content,String title) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        DingtalkConfig dingtalkConfig =  SpringUtil.getBean(DingtalkConfig.class);

        String accessToken = StringPool.EMPTY;
        //如果包含了这个key，获取钉钉接口的token
        if (redisUtil.containsKey(GlobalConstant.DingtalkAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.DingtalkAccessTokenKey);
        }
        else {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(dingtalkConfig.getAppKey());
            request.setAppsecret(dingtalkConfig.getAppSecret());
            request.setHttpMethod(HttpMethod.GET.name());
            OapiGettokenResponse res = client.execute(request);

            accessToken = res.getAccessToken();
        }
        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //获取对应的钉钉用户id
        List<String> idsList = allUser.stream().filter(u ->ObjectUtil.isNotEmpty(u.getDingtalkUserId()) && userIds.contains(u.getId())).map(User::getDingtalkUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.COMMA));

        DingTalkClient sendClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request sendRequest = new OapiMessageCorpconversationAsyncsendV2Request();
        sendRequest.setAgentId(Convert.toLong(dingtalkConfig.getAgentid()));
        sendRequest.setUseridList(touser);
        sendRequest.setToAllUser(false);

        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        //拼接成title:content的形式
        //使用随机数绕过，给同一员工一天只能发送一条内容相同的消息通知，的钉钉接口的校验
        content = title + StringPool.COLON + content + StringPool.LEFT_SQ_BRACKET+ RandomUtil.randomString(4) +StringPool.RIGHT_SQ_BRACKET;
        msg.getText().setContent(content);
        sendRequest.setMsg(msg);

        OapiMessageCorpconversationAsyncsendV2Response rsp = sendClient.execute(sendRequest, accessToken);
        //记录消息推送日志信息
        if (rsp.isSuccess()){//消息发送成功
            String operation = "系统推送钉钉消息成功，具体内容为：【"+ content + "】";
            insertMessageLogInfo(operation);
        }else {
            String operation = "系统推送钉钉消息失败，具体内容为：【"+ content + "】";
            insertMessageLogInfo(operation);
        }
    }

    /**
     * 企业微信--消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param content 消息推送的内容
     * @param title 标题
     */
    @SneakyThrows
    public static void sendWeChatMessageCommon(List<Long> userIds,String content,String title) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        WechatEnterpriseConfig wechatEnterpriseConfig = SpringUtil.getBean(WechatEnterpriseConfig.class);

        String accessToken = StringPool.EMPTY;
        //如果包含了这个key
        if (redisUtil.containsKey(GlobalConstant.WechatAccessTokenKey)) {
            accessToken = redisUtil.get(GlobalConstant.WechatAccessTokenKey);
        }
        else {
            String tokenResult = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wechatEnterpriseConfig.getAppKey() + "&corpsecret=" + wechatEnterpriseConfig.getAppSecret());

            WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);

            accessToken = wechatEnterpriseTokenResult.getAccess_token();
        }

        //获取到需要提醒的人员
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        Map<String,Object> paramMap = new HashMap<>();

        //获取对应的企业微信用户id
        List<String> idsList = allUser.stream().filter(u ->ObjectUtil.isNotEmpty(u.getWechatUserId()) && userIds.contains(u.getId())).map(User::getWechatUserId).collect(Collectors.toList());

        String touser = idsList.stream().map(Convert::toStr).collect(Collectors.joining(StringPool.PIPE));

        paramMap.put("touser",touser);
        paramMap.put("msgtype","text");
        paramMap.put("agentid",wechatEnterpriseConfig.getAgentid());
        //拼接成title:content的形式
        content = title + StringPool.COLON + content;
        Map<String,Object> contentText = new HashMap<>();
        contentText.put("content",content);
        paramMap.put("text",contentText);

        //必须传json数据
        Gson gson = new Gson();
        String jsonMessage = gson.toJson(paramMap);

        String post = HttpUtil.post("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken, jsonMessage);

        //记录日志信息
        String operation = "系统推送企业微信消息成功，具体内容为：【"+ content + "】";
        insertMessageLogInfo(operation);
    }


    /**
     * webhook-消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param content 消息推送的内容
     * @param title 标题
     */
    @SneakyThrows
    public static void sendWebhookMessageCommon(List<Long> userIds,String content,String title) {
        //获取配置信息
        WebhookConfig webhookConfig = SpringUtil.getBean(WebhookConfig.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("msgtype","text");
        Map<String,Object> textMap = new HashMap<>();
        content = title + StringPool.COLON + content;
        textMap.put("content",content);
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        List<String> mentionedList = allUser.stream().filter(u -> ObjectUtil.isNotEmpty(u.getWechatUserId()) && userIds.contains(u.getId())).map(User::getWechatUserId).collect(Collectors.toList());
        textMap.put("mentioned_list",mentionedList);
        paramMap.put("text",textMap);
        //必须传json数据
        Gson gson = new Gson();
        String jsonMessage = gson.toJson(paramMap);
        //建立连接
        String post = HttpUtil.post(webhookConfig.getUrl() + "key=" + webhookConfig.getSecret(), jsonMessage);
        //记录日志信息
        String operation = "系统推送webhook消息成功，具体内容为：【" + content + "】";
        insertMessageLogInfo(operation);
    }


    /**
     * WechatOfficial微信公众号-消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param data 模板数据
     * @param messageContent 消息模板内容
     */
    @SneakyThrows
    public static void sendWechatOfficialMessageCommon(List<Long> userIds, TreeMap<String, TreeMap<String, String>> data, MessageContent messageContent) {
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        WechatOfficalConfig wechatOfficalConfig = SpringUtil.getBean(WechatOfficalConfig.class);

        //获取token
        String accessToken = StringPool.EMPTY;

        String tokenResult = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +
                wechatOfficalConfig.getAppId() + "&secret=" + wechatOfficalConfig.getAppSecret());

        WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);

        accessToken = wechatEnterpriseTokenResult.getAccess_token();

        //获取对应的公众号用户id
        List<User> allUser = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //获取接收者的openid
        List<String> idsList = allUser.stream().filter(u -> userIds.contains(u.getId())).map(User::getWechatOpenId).collect(Collectors.toList());
        Map<String,Object> paramMap = new HashMap<>();
        //公众号消息模板编号
        paramMap.put("template_id",messageContent.getTemplateCode());
        //对应的变量数据
        paramMap.put("data",data);
        for (String touser : idsList) {
            //接收人openid
            paramMap.put("touser",touser);
            //必须传json数据
            Gson gson = new Gson();
            String jsonMessage = gson.toJson(paramMap);
            String post = HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken, jsonMessage);
        }
        //记录日志信息
        String operation = "系统推送微信公众号消息成功，变量内容为：【"+ data.toString() + "】";
        insertMessageLogInfo(operation);
    }


    /**
     * 短信-消息推送方法(公共)
     * @param userIds 消息推送的人员
     * @param templateId 模板id
     * @param data 变量key、value集合
     */
    @SneakyThrows
    public static void sendShortMessageCommon(List<Long> userIds,String templateId ,LinkedHashMap<String, String> data) {
        IUserService userService = SpringUtil.getBean(IUserService.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);

        SmsSender smsSender = SpringUtil.getBean(SmsSender.class);

        //获取用户相关信息
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        //构造短信参数，调用短信服务进行短信发送
        if (userIds.size() > 0) {
            //获取用户id对应的手机号，用户名
            for (Long userId : userIds) {
                User user = userList.stream().filter(u -> userId.equals(u.getId())).findFirst().orElse(new User());
                String mobile = user.getMobile();
                //获取配置信息，并调用短信接口服务
                //异步调用短信接口服务
                CompletableFuture.runAsync(() -> {
                    smsSender.sendCommon(mobile,templateId,data);
                });
            }
        }
        //记录日志信息
        String operation = "系统推送短信消息成功，变量内容为：【"+ data.toString() + "】";
        insertMessageLogInfo(operation);
    }

    /**
     * 插入推送消息的日志信息
     * @param operation 操作内容
     */
    private static void insertMessageLogInfo(String operation){
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
        ILogService logService = SpringUtil.getBean(ILogService.class);
        Log messageLog = new Log();
        messageLog.setCategory(LogCategoryEnum.MESSAGE_SEND.getCode());
        //操作时间
        messageLog.setCreateTime(LocalDateTime.now());
        //操作人
        messageLog.setUsername(user.getName());
        messageLog.setOperation(operation);
        logService.save(messageLog);
    }


    /**
     * 发送催办系统消息
     * @param workflowExtras 当前任务的工作流信息
     */
    public static void sendWorkflowUrgeMessage(List<WorkflowExtra> workflowExtras){
        List<Message> messageList = new ArrayList<>();
        IMessageService messageService = SpringUtil.getBean(IMessageService.class);
        //获取通知人员
        for (WorkflowExtra workflowExtra : workflowExtras) {
            List<Long> userIds = Arrays.stream(workflowExtra.getApproveUserIds().split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
            for (Long userId : userIds) {
                Message message = new Message();
                //将超时提醒显示在工作流审批消息中
                message.setMessageType(MessageType.APPROVE.getCode());
                message.setSendTime(LocalDateTime.now());
                message.setIsRead(YesOrNoEnum.NO.getCode());
                message.setUserId(userId);
                message.setObjectId(workflowExtra.getTaskId());
                String format = StrUtil.format(WORKFLOW_URGE_TEMPLATE, workflowExtra.getTaskName());
                message.setMessageContent(format);
                message.setProcessId(workflowExtra.getProcessId());
                message.setSchemaId(workflowExtra.getSchemaId());
                messageList.add(message);
            }
        }

        messageService.saveBatch(messageList);
    }

    /**
     * 发送催办短信
     * @param workflowExtras 当前任务的工作流信息
     */
    public static void sendWorkflowUrgeSms(List<WorkflowExtra> workflowExtras){
        IUserService userService = SpringUtil.getBean(IUserService.class);
        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
        SmsSender smsSender = SpringUtil.getBean(SmsSender.class);
        //获取用户相关信息
        List<User> userList = redisUtil.get(GlobalConstant.USER_CACHE_KEY, new TypeReference<List<User>>() {
        });
        //如果缓存中不存在用户信息，就直接去数据库查询,并保存到缓存中去
        if (userList.size() == 0) {
            userList = userService.list();
            redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
        }
        for (WorkflowExtra workflowExtra : workflowExtras) {
            //获取通知人员
            List<Long> userIds = Arrays.stream(workflowExtra.getApproveUserIds().split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
            //构造短信参数，调用短信服务进行短信发送
            if (userIds.size() > 0) {
                //获取用户id对应的手机号，用户名
                for (Long userId : userIds) {
                    User user = userList.stream().filter(u -> userId.equals(u.getId())).findFirst().orElse(new User());
                    String mobile = user.getMobile();
                    //调用短信接口服务,还需要修改，暂时用验证码的测试
//                smsSender.sendCaptcha(mobile, workflowExtras.getTaskName());
                    smsSender.sendTimeout(mobile, workflowExtra.getTaskName());
                }
            }
        }
    }

}
